说明:利用
Objective-C
的动态运行时分配机制,你可以为现有的类添加方法
或计算属性
,这种机制称为类别(category)
。
- 可以在类中添加属性(
@property
),且只能是计算属性
(不能添加实例变量
)- 可以向一个
类
添加任意数量的类别
类别
可以访问其扩展的类的实例变量
总结:我将
类别
分3种
种类 | @interface |
@implementation |
---|---|---|
类别 | @interface 类名(类别名) |
@implementation 类名(类别名) |
类扩展(匿名类别) | @interface 类名() |
无 |
前向引导 | @interface 类名(类别名) |
@implementation 类名 |
12.1 创建类别
说明:可以为人和类添加新的方法,包括那些没有源代码的类。
技巧:通常把类别代码放在独立
的文件中,通常以类名称+类别名称
的风格命名。
12.1.1 开始创建类别独立文件
说明:使用
Xcode
往项目中添加类别非常容易,甚至可以类名称+类别名称
命名类别文件。
- 新建文件
- 选择模版
- 文件相关
- 完成
12.1.2 @interface部分
NSString+NumberConvience.h
1 |
|
12.1.3 @implementation部分
NSString+NumberConvience.m
1 |
|
main.m
1 |
|
12.1.4 类别的缺陷
说明:类别有2个局限性
- 无法向类中添加实例变量
- 当类别添加的方法和类中原有的方法重名时,类别具有更高的优先级
解决命名冲突:可以在类别的方法名中添加一个前缀,以确保不会发生名称冲突。
添加实例变量:使用全局字典来存储对象与想关联的额外变量之间的映射。
12.1.5 类别的优势
说明:类别主要有3个用途
- 将类的实现代码分散到多个不同文件或框架中
- 创建对私有方法的前向引用
- 向对象添加非正式协议(informal protocol)
12.1.6 类扩展
说名:
类扩展(class extension)
是一个特殊的类别
,它不需要命名(只有@interface
没有@implementation
)。
- 可以包含源代码的类中使用
- 可以添加实例变量
- 可以将只读权限改成可读写的权限
- 创建数量不限
信息隐藏:分2种情况
类扩展 所在文件 |
可访问性 |
---|---|
扩展的目标类的@implementation 所在.m 文件 |
目标类的内部 |
单独的私有.h 文件 |
目标类的内部、目标类的子类和友类 |
注意:可以拥有多个
类扩展
,不过这样会引发很难察觉的bug
,所以请理智使用。
Things.h:类的@interface
1 |
|
Things.m:类的@implementation
和类扩展
1 |
|
main.m:使用被扩展后的NSString
1 |
|
12.2 利用类别分散实现代码
说明:如果想将大型的单个类分散到多个不同的
.m
文件中,可以使用类别
。
举例:AppKit
中的NSWindow
,拥有大量的类别
声明
@interface NSWindow(NSKeyboardUI)
@interface NSWindow(NSToolbarSupport)
@interface NSWindow(NSDrag)
@interface NSWindow(NSCarbonExtensions)
扩展:
类别
还可以将方法
分散到逻辑群组
中,使编程人员可以更加容易地阅读头文件
。
在项目中使用类别
说明:将类的
类别
的实现部分分散在三个独立的文件中。
CategoryThing.h:类的@interface
和3个类别的@interface
1 |
|
CategoryThing.m:类的@implementation
1 |
|
CategoryThing+Thing1.m:类别Thing1的@implementation
1 |
|
CategoryThing+Thing2.m:类别Thing2的@implementation
1 |
|
CategoryThing+Thing3.m:类别Thing3的@implementation
1 |
|
main.m:调用类
通过类别
扩展的功能
1 |
|
12.3 通过类别创建前向引用
背景:
Objective-C
的私有方法
分两种
- 如果在一个类的
@implementation
部分定义了某个方法,而对应的@interface
部分没有相应的方法声明- 通过
类扩展(匿名类别)
扩展的方法然而,
O-C
并不真的支持私有方法
,所以私有方法
仍然可以通过对象调用,只不过这时Xcode
会给出警告。
说明:当从外部访问某个类
的私有方法
时,为了避免Xcode
给出警告,可以通过类别
补充一个声明,即前向引导
。
扩展:实际上,苹果公司官网在知道方针中指出,应用程序不能访问类里面的私有变量和方法,如果你的应用程序有这样的行为,那么苹果公司会拒绝让它上架。
main.m:在最前面创建类别
来补充私有方法
的声明
1 | @interface Car (Private) |
Car.m:方法的实现部分是Car的私有方法
1 | @implementation Car |
12.4 非正式协议和委托类别
委托:将某些工作交给另一个类执行就叫做
委托(delegate)
。
委托对象:委托
技术中,被委托用来执行某些工作的对象
。
说明:除了通过继承
创建委托对象
外,可以通过类别
扩展NSObject
(即创建了一个非正式协议
),使其获得委托方法
,从而将任何对象都变成委托对象
。
12.4.1 iTunesFinder项目
说明:用来说明
Cocoa
中是如何使用委托
技术的。
Bonjour
说明:查找由
Bonjour
发布的网络服务的Cocoa类
是NSNetServiceBrowser
。
用法:告诉网络服务浏览器
你需要的服务,并为其提供一个委托对象
。浏览器对象
将会向该委托对象
发送消息,告知其发现新服务的时间。
ITunesFinder.h
1 |
|
ITunesFinder.m
1 |
|
main.m
1 |
|
12.4.2 委托和类别
说明:除了通过
继承
创建委托对象
外,可以通过类别
扩展NSObject
(即创建了一个非正式协议
),使其获得委托方法
,从而将任何对象都变成委托对象
。
1 | @interface NSObject (NSNetServerBrowserDelegateMethods) |
12.4.3 响应选择器
说明:
NSNetServiceBrowser
为了确定其委托对象
是否能够处理那些发送给它的消息,会首先检查对象,询问其能否响应该选择器,是泽发送消息,否则忽略这个委托对象,程序继续运行。
选择器(selector)
说明:只是一个方法名称,但以
Objective-C
运行时使用的特殊方式编码,以快速执行查询。
语法:@selector(方法名)
用途:NSObject
提供了一个名为responendsToSelector
的方法,该方法询问对象以确定其是否能够响应某个特定的消息。
1 | Car *car = [[Car alloc] init]; |
12.4.4 选择器的其它应用
说明:选择器可以
- 被传递
- 作为方法的参数
- 作为实例变量被存储
举个例子:
Foundation
框架中的NSTimer